#include "TFMsgProcess.h"

#include <core/Utility.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/MessageParserTool.h>
#include <qbprotocol/include/SSFIModel.h>
#include <qbprotocol/include/rdProto.h>

#include "qbprotocol/include/SSQBModel.h"

using namespace qb;

namespace {
#define Reg_Func(ID) \
  qbBase::getMessageBond()->RegisterDecodeFunc(ID, qbmsg::tf::ExtracFunc)
#define DelPtr(FUNC, TYPE)               \
  case FUNC: {                           \
    TYPE* p = static_cast<TYPE*>(toDel); \
    delete p;                            \
    return nullptr;                      \
  } break;

void* delAck(int func, void* toDel) {
  switch (func) {
    DelPtr(E_FID_QB_TF_CONTACT_INFO_REQ, xQBTFContactInfoList_c);
    DelPtr(E_FID_QB_TF_PRICE_REQ_V2, xQBTFPriceList_c);
    DelPtr(E_FID_QB_TF_PRICE_PUSH_V3, xQBTFPriceList_c);
    DelPtr(E_FID_QB_TF_REALTIME, xQBTFRealTimeList_c);
    DelPtr(E_FID_QB_TF_TICK_REQ, xQBTFTickList_c);
    DelPtr(E_FID_QB_TF_REFBOND_REQ, xQBRefBondList_c);
    DelPtr(E_FID_QB_HISSPREAD_CONVERT_FACTOR_REQ, xConvertFactorsAck_c);
    DelPtr(E_FID_QB_NAT_DEBT_ACTIVE_BOND_REQ, xNatDebtActiveBondAck_c);
    DelPtr(E_FID_TF_SETTLEMENT_PRICE_REQ, xQBTfSettlementPriceAck);
    default:
      break;
  }
  return toDel;
}
}  // namespace

void qbmsg::tf::InitDecodeFuncs() {
  Reg_Func(E_FID_QB_TF_CONTACT_INFO_REQ);
  Reg_Func(E_FID_QB_TF_PRICE_REQ_V2);
  Reg_Func(E_FID_QB_TF_PRICE_PUSH_V3);
  Reg_Func(E_FID_QB_TF_REALTIME);
  Reg_Func(E_FID_QB_TF_TICK_REQ);
  Reg_Func(E_FID_QB_TF_REFBOND_REQ);
  Reg_Func(E_FID_QB_HISSPREAD_CONVERT_FACTOR_REQ);
  Reg_Func(E_FID_QB_NAT_DEBT_ACTIVE_BOND_REQ);
  Reg_Func(E_FID_TF_SETTLEMENT_PRICE_REQ);
}

void qbmsg::tf::EncodeFunc(qb::proto::Message& msg, qb::SSRequestMsg* req) {
  switch (req->m_FuncID) {
    case E_FID_QB_TF_CONTACT_INFO_REQ: {  // 50043 国债期货合约基本信息
      qb::proto::Message::List sublist;
      QBTFContactInfoReq_t* pdata = (QBTFContactInfoReq_t*)req->m_pRequest;
      for (std::list<xQBTFInstrument_c>::const_iterator it =
               pdata->m_List.begin();
           it != pdata->m_List.end(); ++it) {
        qb::proto::VariantMap listmsg;
        listmsg.setString("TF_Key", it->m_TF_Key);
        listmsg.setString("InstrumentID", it->m_InstrumentID);
        sublist.push_back(listmsg);
      }
      qb::proto::VariantMap submsg;
      submsg.SetList("List", sublist);
      submsg.setString("Version", pdata->m_Version);
      msg.SetMap("xQBTFContactInfoReq", submsg);
      break;
    }
    case E_FID_QB_TF_PRICE_REQ_V2:     // 50381 国债期货行情查询
    case E_FID_QB_TF_PRICE_PUSH_V3: {  // 50382
      msg.setString("IMQ_RequestType", "NDF_QUOTATION_V2");
      qb::proto::Message::List instrument_list;
      QBTFPriceReq_t* pdata = (QBTFPriceReq_t*)req->m_pRequest;
      for (std::list<xQBTFInstrument_c>::const_iterator it =
               pdata->m_List.begin();
           it != pdata->m_List.end(); ++it) {
        qb::proto::VariantMap msglist;
        msglist.setString("IMQ_InstrumentID", it->m_InstrumentID);
        instrument_list.push_back(msglist);
      }
      msg.setList("IMQ_InstrumentID", instrument_list);
      break;
    }
    case E_FID_QB_TF_REALTIME: {  // 50047 国债期货分时行情查询 anson
      msg.setString("IMQ_RequestType", "TF_K_LINE_1M");
      QBTFRealTimeReq_t* pdata = (QBTFRealTimeReq_t*)req->m_pRequest;
      msg.setString("IMQ_TF_KEY", pdata->m_TF_Key);
      msg.setString("IMQ_TF_ID", pdata->m_TF_ID);
      msg.setInt32("IMQ_BeginTime", pdata->m_beginTime);
      msg.setInt32("IMQ_EndTime", pdata->m_endTime);
      break;
    }
    case E_FID_QB_TF_TICK_REQ: {  // 50064 查询Tick
      xQBTFTickReq_t* pdata = (xQBTFTickReq_t*)req->m_pRequest;
      msg.setString("IMQ_RequestType", "TF_K_TICK");
      msg.setString("IMQ_TF_KEY", pdata->m_TF_Key);
      msg.setInt32("IMQ_BeginTime", pdata->m_beginTime);
      msg.setInt32("IMQ_EndTime", pdata->m_endTime);
      msg.setInt32("IMQ_Limit", pdata->m_limitCount);
      break;
    }
    case E_FID_QB_TF_REFBOND_REQ: {  // 50044 请求国债期货相关的现券
      qb::proto::Message::List sublist;
      QBRefBondReq_t* pdata = (QBRefBondReq_t*)req->m_pRequest;
      qb::proto::VariantMap submsg;
      submsg.SetString("TF_Key", pdata->m_TF_Key);
      msg.SetMap("xQBRefBondReq", submsg);
      break;
    }
    case E_FID_QB_HISSPREAD_CONVERT_FACTOR_REQ: {  // 50339
                                                   // 历史价差转换因子计算请求
                                                   // FE
      qb::proto::Message::List conver_req_list;
      xConvertFactorsReq_c* pdata = (xConvertFactorsReq_c*)req->m_pRequest;
      for (std::list<xConvertFactorsUnit_c>::const_iterator it =
               pdata->m_List.begin();
           it != pdata->m_List.end(); ++it) {
        qb::proto::VariantMap msgListUnit;
        msgListUnit.setString("bondKey", it->m_bondKey);
        msgListUnit.setString("deliverDate", it->m_deliverDate);
        conver_req_list.push_back(msgListUnit);
      }
      msg.setList("convertFactors", conver_req_list);
      break;
    }
    case E_FID_QB_NAT_DEBT_ACTIVE_BOND_REQ: {  // 50658 查询国债期货的活跃券
      xNatDebtActiveBondReq_t* pdata =
          (xNatDebtActiveBondReq_t*)req->m_pRequest;
      qb::proto::VariantMap submsg;
      submsg.SetString("UserId", pdata->m_UserId);
      submsg.SetString("UserAccount", pdata->m_UserAccount);
      msg.SetMap("xNatDebtActiveBondReq", submsg);
      break;
    }
    case E_FID_TF_SETTLEMENT_PRICE_REQ: {
      xQBTfSettlementPriceReq* pdata =
          (xQBTfSettlementPriceReq*)req->m_pRequest;
      qb::proto::VariantMap submsg;
      submsg.SetString("Start", pdata->m_Start);
      submsg.SetString("End", pdata->m_End);
      msg.SetMap("xQBTfSettlementPriceReq", submsg);
    } break;
    default:
      break;
  }
}

void* qbmsg::tf::ExtracFunc(int func, const ProtoMessage& msg, void* toDel) {
  if (toDel != nullptr) return delAck(func, toDel);

  switch (func) {
    case E_FID_QB_TF_CONTACT_INFO_REQ: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBTFContactInfoList_c* ptr = new xQBTFContactInfoList_c;
      if (!ptr) return nullptr;

      msg.GetUInt32("NatChangeDate", ptr->m_NatChangeDate);

      xQBTFContactInfo_c contact_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&contact_unit, 0, sizeof(xQBTFContactInfo_c));
        const ProtoMap& msgmap = *it;
        FIELDCOPY(contact_unit.m_TF_Key,
                  CParserTool::GetString(msgmap, "TF_Key"));
        FIELDCOPY(contact_unit.m_TF_ID,
                  CParserTool::GetString(msgmap, "TF_ID"));
        FIELDCOPY(contact_unit.m_TF_ShortName,
                  CParserTool::GetString(msgmap, "TF_ShortName"));
        msgmap.GetInt32("Delivery_Month", contact_unit.m_Delivery_Month);
        msgmap.GetUInt32("Last_Trading_Day", contact_unit.m_Last_Trading_Day);
        msgmap.GetUInt32("Delivery_Date", contact_unit.m_Delivery_Date);
        msgmap.GetUInt32("BondTerm", contact_unit.m_BondTerm);
        msgmap.GetUInt32("Deliverable_maturity_Start",
                         contact_unit.m_Deliverable_maturity_Start);
        msgmap.GetUInt32("Deliverable_maturity_End",
                         contact_unit.m_Deliverable_maturity_End);
        FIELDCOPY(contact_unit.m_Quoted_Way,
                  CParserTool::GetString(msgmap, "Quoted_Way"));
        msgmap.GetFloat("Min_Change", contact_unit.m_Min_Change);
        FIELDCOPY(contact_unit.m_Trading_Time,
                  CParserTool::GetString(msgmap, "Trading_Time"));
        FIELDCOPY(contact_unit.m_Last_Day_Trading_Time,
                  CParserTool::GetString(msgmap, "Last_Day_Trading_Time"));
        msgmap.GetFloat("Price_Limit", contact_unit.m_Price_Limit);
        msgmap.GetFloat("Lowest_Margins", contact_unit.m_Lowest_Margins);
        FIELDCOPY(contact_unit.m_Delivery_Way,
                  CParserTool::GetString(msgmap, "Delivery_Way"));
        FIELDCOPY(contact_unit.m_Listed_Market,
                  CParserTool::GetString(msgmap, "Listed_Market"));
        FIELDCOPY(contact_unit.m_Is_Tradable,
                  CParserTool::GetString(msgmap, "Is_Tradable"));
        ptr->m_List.push_back(contact_unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_TF_PRICE_REQ_V2: {
      ProtoList msglist;
      if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

      xQBTFPriceList_c* ptr = new xQBTFPriceList_c;
      if (!ptr) return nullptr;

      xQBTFPriceUnit_c tfprice_unit;
      double dval = 0;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&tfprice_unit, 0, sizeof(xQBTFPriceUnit_c));
        const ProtoMap& msgmap = *it;

        FIELDCOPY(tfprice_unit.m_TradingDay,
                  CParserTool::GetString(msgmap, "td"));
        FIELDCOPY(tfprice_unit.m_InstrumentID,
                  CParserTool::GetString(msgmap, "iid"));
        FIELDCOPY(tfprice_unit.m_ExchangeID,
                  CParserTool::GetString(msgmap, "eid"));
        FIELDCOPY(tfprice_unit.m_ExchangeInstID,
                  CParserTool::GetString(msgmap, "eiid"));
        if (msgmap.GetDouble("pri", dval))
          tfprice_unit.m_LastPrice = static_cast<float>(dval);
        if (msgmap.GetDouble("psp", dval))
          tfprice_unit.m_PreSettlementPrice = static_cast<float>(dval);
        if (msgmap.GetDouble("pcp", dval))
          tfprice_unit.m_PreClosePrice = static_cast<float>(dval);
        msgmap.GetDouble("poi", tfprice_unit.m_PreOpenInterest);
        if (msgmap.GetDouble("op", dval))
          tfprice_unit.m_OpenPrice = static_cast<float>(dval);
        if (msgmap.GetDouble("hp", dval))
          tfprice_unit.m_HighestPrice = static_cast<float>(dval);
        if (msgmap.GetDouble("lp", dval))
          tfprice_unit.m_LowestPrice = static_cast<float>(dval);
        msgmap.GetInt32("vol", tfprice_unit.m_Volume);
        msgmap.GetDouble("tn", tfprice_unit.m_Turnover);
        msgmap.GetInt32("lv", tfprice_unit.m_LastVolume);
        msgmap.GetInt32("iv", tfprice_unit.m_IncrementVolume);
        msgmap.GetDouble("it", tfprice_unit.m_IncrementTurnover);
        msgmap.GetDouble("io", tfprice_unit.m_IncrementOpenInterest);

        msgmap.GetDouble("lt", tfprice_unit.m_LastTurnover);
        msgmap.GetDouble("oi", tfprice_unit.m_OpenInterest);
        if (msgmap.GetDouble("cp", dval))
          tfprice_unit.m_ClosePrice = static_cast<float>(dval);
        if (msgmap.GetDouble("sp", dval))
          tfprice_unit.m_SettlementPrice = static_cast<float>(dval);
        if (msgmap.GetDouble("ulp", dval))
          tfprice_unit.m_UpperLimitPrice = static_cast<float>(dval);
        if (msgmap.GetDouble("llp", dval))
          tfprice_unit.m_LowerLimitPrice = static_cast<float>(dval);
        if (msgmap.GetDouble("cd", dval))
          tfprice_unit.m_CurrDelta = static_cast<float>(dval);
        if (msgmap.GetDouble("pd", dval))
          tfprice_unit.m_PreDelta = static_cast<float>(dval);
        FIELDCOPY(tfprice_unit.m_UpdateTime,
                  CParserTool::GetString(msgmap, "ut"));
        msgmap.GetInt32("um", tfprice_unit.m_UpdateMillisec);
        if (msgmap.GetDouble("ap", dval))
          tfprice_unit.m_AveragePrice = static_cast<float>(dval);
        if (msgmap.GetDouble("bp1", dval))
          tfprice_unit.m_BidPrice1 = static_cast<float>(dval);
        msgmap.GetInt32("bv1", tfprice_unit.m_BidVolume1);
        if (msgmap.GetDouble("ap1", dval))
          tfprice_unit.m_AskPrice1 = static_cast<float>(dval);
        msgmap.GetInt32("av1", tfprice_unit.m_AskVolume1);
        if (msgmap.GetDouble("bp2", dval))
          tfprice_unit.m_BidPrice2 = static_cast<float>(dval);
        msgmap.GetInt32("bv2", tfprice_unit.m_BidVolume2);
        if (msgmap.GetDouble("ap2", dval))
          tfprice_unit.m_AskPrice2 = static_cast<float>(dval);
        msgmap.GetInt32("av2", tfprice_unit.m_AskVolume2);
        if (msgmap.GetDouble("bp3", dval))
          tfprice_unit.m_BidPrice3 = static_cast<float>(dval);
        msgmap.GetInt32("bv3", tfprice_unit.m_BidVolume3);
        if (msgmap.GetDouble("ap3", dval))
          tfprice_unit.m_AskPrice3 = static_cast<float>(dval);
        msgmap.GetInt32("av3", tfprice_unit.m_AskVolume3);
        if (msgmap.GetDouble("bp4", dval))
          tfprice_unit.m_BidPrice4 = static_cast<float>(dval);
        msgmap.GetInt32("bv4", tfprice_unit.m_BidVolume4);
        if (msgmap.GetDouble("ap4", dval))
          tfprice_unit.m_AskPrice4 = static_cast<float>(dval);
        msgmap.GetInt32("av4", tfprice_unit.m_AskVolume4);
        if (msgmap.GetDouble("bp5", dval))
          tfprice_unit.m_BidPrice5 = static_cast<float>(dval);
        msgmap.GetInt32("bv5", tfprice_unit.m_BidVolume5);
        if (msgmap.GetDouble("ap5", dval))
          tfprice_unit.m_AskPrice5 = static_cast<float>(dval);
        msgmap.GetInt32("av5", tfprice_unit.m_AskVolume5);
        msgmap.GetBool("ih", tfprice_unit.m_IsHoliday);

        ptr->m_List.push_back(tfprice_unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_TF_PRICE_PUSH_V3: {
      const char* td = "1";
      const char* iid = "2";
      const char* eid = "3";
      const char* eiid = "4";
      const char* pri = "5";
      const char* psp = "6";
      const char* pcp = "7";
      const char* poi = "8";
      const char* op = "9";
      const char* hp = "10";
      const char* lp = "11";
      const char* vol = "12";
      const char* tn = "13";
      const char* lv = "14";
      const char* iv = "15";
      const char* it = "16";
      const char* io = "17";
      const char* lt = "18";
      const char* oi = "19";
      const char* cp = "20";
      const char* sp = "21";
      const char* ulp = "22";
      const char* llp = "23";
      const char* cd = "24";
      const char* pd = "25";
      const char* ut = "26";
      const char* um = "27";
      const char* ap = "28";
      const char* bp1 = "29";
      const char* bv1 = "30";
      const char* ap1 = "31";
      const char* av1 = "32";
      const char* bp2 = "33";
      const char* bv2 = "34";
      const char* ap2 = "35";
      const char* av2 = "36";
      const char* bp3 = "37";
      const char* bv3 = "38";
      const char* ap3 = "39";
      const char* av3 = "40";
      const char* bp4 = "41";
      const char* bv4 = "42";
      const char* ap4 = "43";
      const char* av4 = "44";
      const char* bp5 = "45";
      const char* bv5 = "46";
      const char* ap5 = "47";
      const char* av5 = "48";
      const char* ih = "49";

      qb::base::msg::Raw raw;
      if (!msg.GetRaw("list", raw)) return nullptr;

      xQBTFPriceList_c* ptr = new xQBTFPriceList_c;
      if (!ptr) return nullptr;

      qb::proto::VariantTableDecoder msglist;
      if (!msglist.decode((const char*)raw.Data, raw.Length)) return nullptr;

      xQBTFPriceUnit_c tfprice_unit;
      double dval = 0;
      for (auto itList = msglist.begin(); itList != msglist.end(); ++itList) {
        memset(&tfprice_unit, 0, sizeof(xQBTFPriceUnit_c));
        const qb::proto::VariantRecord* msgmap = *itList;

        FIELDCOPY(tfprice_unit.m_TradingDay,
                  CParserTool::GetString(msgmap, td));
        FIELDCOPY(tfprice_unit.m_InstrumentID,
                  CParserTool::GetString(msgmap, iid));
        FIELDCOPY(tfprice_unit.m_ExchangeID,
                  CParserTool::GetString(msgmap, eid));
        FIELDCOPY(tfprice_unit.m_ExchangeInstID,
                  CParserTool::GetString(msgmap, eiid));
        if (msgmap->getDouble(pri, dval))
          tfprice_unit.m_LastPrice = static_cast<float>(dval);
        if (msgmap->getDouble(psp, dval))
          tfprice_unit.m_PreSettlementPrice = static_cast<float>(dval);
        if (msgmap->getDouble(pcp, dval))
          tfprice_unit.m_PreClosePrice = static_cast<float>(dval);
        msgmap->getDouble(poi, tfprice_unit.m_PreOpenInterest);
        if (msgmap->getDouble(op, dval))
          tfprice_unit.m_OpenPrice = static_cast<float>(dval);
        if (msgmap->getDouble(hp, dval))
          tfprice_unit.m_HighestPrice = static_cast<float>(dval);
        if (msgmap->getDouble(lp, dval))
          tfprice_unit.m_LowestPrice = static_cast<float>(dval);
        msgmap->getInt32(vol, tfprice_unit.m_Volume);
        msgmap->getDouble(tn, tfprice_unit.m_Turnover);
        msgmap->getInt32(lv, tfprice_unit.m_LastVolume);
        msgmap->getInt32(iv, tfprice_unit.m_IncrementVolume);
        msgmap->getDouble(it, tfprice_unit.m_IncrementTurnover);
        msgmap->getDouble(io, tfprice_unit.m_IncrementOpenInterest);

        msgmap->getDouble(lt, tfprice_unit.m_LastTurnover);
        msgmap->getDouble(oi, tfprice_unit.m_OpenInterest);
        if (msgmap->getDouble(cp, dval))
          tfprice_unit.m_ClosePrice = static_cast<float>(dval);
        if (msgmap->getDouble(sp, dval))
          tfprice_unit.m_SettlementPrice = static_cast<float>(dval);
        if (msgmap->getDouble(ulp, dval))
          tfprice_unit.m_UpperLimitPrice = static_cast<float>(dval);
        if (msgmap->getDouble(llp, dval))
          tfprice_unit.m_LowerLimitPrice = static_cast<float>(dval);
        if (msgmap->getDouble(cd, dval))
          tfprice_unit.m_CurrDelta = static_cast<float>(dval);
        if (msgmap->getDouble(pd, dval))
          tfprice_unit.m_PreDelta = static_cast<float>(dval);
        FIELDCOPY(tfprice_unit.m_UpdateTime,
                  CParserTool::GetString(msgmap, ut));
        msgmap->getInt32(um, tfprice_unit.m_UpdateMillisec);
        if (msgmap->getDouble(ap, dval))
          tfprice_unit.m_AveragePrice = static_cast<float>(dval);
        if (msgmap->getDouble(bp1, dval))
          tfprice_unit.m_BidPrice1 = static_cast<float>(dval);
        msgmap->getInt32(bv1, tfprice_unit.m_BidVolume1);
        if (msgmap->getDouble(ap1, dval))
          tfprice_unit.m_AskPrice1 = static_cast<float>(dval);
        msgmap->getInt32(av1, tfprice_unit.m_AskVolume1);
        if (msgmap->getDouble(bp2, dval))
          tfprice_unit.m_BidPrice2 = static_cast<float>(dval);
        msgmap->getInt32(bv2, tfprice_unit.m_BidVolume2);
        if (msgmap->getDouble(ap2, dval))
          tfprice_unit.m_AskPrice2 = static_cast<float>(dval);
        msgmap->getInt32(av2, tfprice_unit.m_AskVolume2);
        if (msgmap->getDouble(bp3, dval))
          tfprice_unit.m_BidPrice3 = static_cast<float>(dval);
        msgmap->getInt32(bv3, tfprice_unit.m_BidVolume3);
        if (msgmap->getDouble(ap3, dval))
          tfprice_unit.m_AskPrice3 = static_cast<float>(dval);
        msgmap->getInt32(av3, tfprice_unit.m_AskVolume3);
        if (msgmap->getDouble(bp4, dval))
          tfprice_unit.m_BidPrice4 = static_cast<float>(dval);
        msgmap->getInt32(bv4, tfprice_unit.m_BidVolume4);
        if (msgmap->getDouble(ap4, dval))
          tfprice_unit.m_AskPrice4 = static_cast<float>(dval);
        msgmap->getInt32(av4, tfprice_unit.m_AskVolume4);
        if (msgmap->getDouble(bp5, dval))
          tfprice_unit.m_BidPrice5 = static_cast<float>(dval);
        msgmap->getInt32(bv5, tfprice_unit.m_BidVolume5);
        if (msgmap->getDouble(ap5, dval))
          tfprice_unit.m_AskPrice5 = static_cast<float>(dval);
        msgmap->getInt32(av5, tfprice_unit.m_AskVolume5);
        // msgmap.GetBool("ih", tfprice_unit.m_IsHoliday);
        int is_holiday = 0;
        msgmap->getInt32(ih, is_holiday);
        tfprice_unit.m_IsHoliday = (is_holiday == 1);

        ptr->m_List.push_back(tfprice_unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_TF_REALTIME: {
      ProtoList msglist;
      if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

      xQBTFRealTimeList_c* ptr = new xQBTFRealTimeList_c;
      if (!ptr) return nullptr;

      xQBTFRealTimeUnit_c realtime_unit;
      double dval = 0;
      class Util {
       public:
        static bool DecodeDoubleValue(const ProtoMap& map, const char* name,
                                      float& value) {
          double dval = 0.0;
          if (map.GetDouble(name, dval)) {
            value = static_cast<float>(dval);
            return true;
          }
          return false;
        }
      };
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&realtime_unit, 0, sizeof(xQBTFRealTimeUnit_c));
        const ProtoMap& msgmap = *it;

        // 按照名称顺序访问,性能最好,参见proto_message.cpp中的FieldTable::getFieldValue
        msgmap.GetDouble("Amount_Total", realtime_unit.m_Amount_Total);
        msgmap.GetDouble("AskPrice1", realtime_unit.m_AskPrice1);
        msgmap.GetInt32("AskVolume1", realtime_unit.m_AskVolume1);
        msgmap.GetDouble("BidPrice1", realtime_unit.m_BidPrice1);
        msgmap.GetInt32("BidVolume1", realtime_unit.m_BidVolume1);
        Util::DecodeDoubleValue(msgmap, "Close", realtime_unit.m_Close);
        Util::DecodeDoubleValue(msgmap, "High", realtime_unit.m_High);
        Util::DecodeDoubleValue(msgmap, "Low", realtime_unit.m_Low);
        Util::DecodeDoubleValue(msgmap, "Open", realtime_unit.m_Open);
        msgmap.GetDouble("Positions", realtime_unit.m_Positions);
        FIELDCOPY(realtime_unit.m_TF_ID,
                  CParserTool::GetString(msgmap, "TF_ID"));
        FIELDCOPY(realtime_unit.m_TF_Key,
                  CParserTool::GetString(msgmap, "TF_Key"));
        CParserTool::MessageGetTime(msgmap, "Tran_Time",
                                    realtime_unit.m_Tran_Time);
        msgmap.GetInt32("Tran_Time_Msec", realtime_unit.m_Tran_Time_Msec);
        msgmap.GetDouble("Volume", realtime_unit.m_Volume);
        msgmap.GetDouble("Volume_Total", realtime_unit.m_Volume_Total);
        ptr->m_List.push_back(realtime_unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_TF_TICK_REQ: {
      ProtoList msglist;
      if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

      xQBTFTickList_c* ptr = new xQBTFTickList_c;
      if (!ptr) return nullptr;

      xQBTFTickUnit_c tick_unit;
      double dval = 0;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&tick_unit, 0, sizeof(xQBTFTickUnit_c));
        const ProtoMap& msgmap = *it;
        FIELDCOPY(tick_unit.m_TradingDay,
                  CParserTool::GetString(msgmap, "TradingDay"));
        FIELDCOPY(tick_unit.m_TF_Key, CParserTool::GetString(msgmap, "TF_Key"));
        FIELDCOPY(tick_unit.m_InstrumentID,
                  CParserTool::GetString(msgmap, "TF_ID"));
        if (msgmap.GetDouble("LastPrice", dval))
          tick_unit.m_LastPrice = static_cast<float>(dval);
        msgmap.GetDouble("IncrementInterest", tick_unit.m_IncrementInterest);
        msgmap.getInt32("IncrementVolume", tick_unit.m_LastVolume);
        FIELDCOPY(tick_unit.m_UpdateTime,
                  CParserTool::GetString(msgmap, "UpdateTime"));
        msgmap.getInt32("UpdateMillisec", tick_unit.m_UpdateMillisec);
        if (msgmap.GetDouble("BidPrice1", dval))
          tick_unit.m_BidPrice1 = static_cast<float>(dval);
        if (msgmap.GetDouble("AskPrice1", dval))
          tick_unit.m_AskPrice1 = static_cast<float>(dval);
        if (msgmap.GetDouble("AveragePrice", dval))
          tick_unit.m_AveragePrice = static_cast<float>(dval);
        ptr->m_List.push_back(tick_unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_TF_REFBOND_REQ: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBRefBondList_c* ptr = new xQBRefBondList_c;
      if (!ptr) return nullptr;

      xQBRefBond_c refbond_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&refbond_unit, 0, sizeof(xQBRefBond_c));
        const ProtoMap& msgmap = *it;
        FIELDCOPY(refbond_unit.m_TF_Key,
                  CParserTool::GetString(msgmap, "TF_Key"));
        FIELDCOPY(refbond_unit.m_TF_ID,
                  CParserTool::GetString(msgmap, "TF_ID"));
        FIELDCOPY(refbond_unit.m_Bond_Key,
                  CParserTool::GetString(msgmap, "Bond_Key"));
        msgmap.GetFloat("Conversion_Factor", refbond_unit.m_Conversion_Factor);
        ptr->m_List.push_back(refbond_unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_HISSPREAD_CONVERT_FACTOR_REQ: {
      ProtoList sublist;
      if (!msg.GetList("convertFactors", sublist)) return nullptr;

      xConvertFactorsAck_c* ptr = new xConvertFactorsAck_c;
      if (!ptr) return nullptr;

      for (ProtoList::const_iterator it = sublist.begin(); it != sublist.end();
           ++it) {
        const ProtoMap& msgmap = *it;
        xConvertFactorsUnit_c convertFactorItem;
        FIELDCOPY(convertFactorItem.m_bondKey,
                  CParserTool::GetString(msgmap, "bondKey"));
        msgmap.GetDouble("convertFactor", convertFactorItem.m_convertFactors);
        FIELDCOPY(convertFactorItem.m_deliverDate,
                  CParserTool::GetString(msgmap, "deliverDate"));
        ptr->m_List.push_back(convertFactorItem);
      }
      return ptr;
      break;
    }
    case E_FID_QB_NAT_DEBT_ACTIVE_BOND_REQ: {
      xNatDebtActiveBondAck_c* ptr = new xNatDebtActiveBondAck_c;
      if (!ptr) return nullptr;

      for (int nL = 0; nL < 3; nL++) {
        ProtoList submsg_m_List;
        if (nL == 0) {
          if (!msg.GetList("ListFive", submsg_m_List)) continue;
        } else if (nL == 1) {
          if (!msg.GetList("ListTen", submsg_m_List)) continue;
        } else {
          if (!msg.GetList("ListTwo", submsg_m_List)) continue;
        }
        std::list<TW_BOND>& lstBond =
            nL == 0 ? ptr->m_ListFive
                    : ((nL == 1) ? ptr->m_ListTen : ptr->m_ListTwo);
        for (ProtoList::const_iterator it = submsg_m_List.begin();
             it != submsg_m_List.end(); ++it) {
          if (it->Type != ProtoValue::VAR_MAP) continue;
          const ProtoMap& msgBond = *it;
          TW_BOND bondItem;
          FIELDCOPY(bondItem.m_Bond_Type,
                    CParserTool::GetString(msgBond, "Bond_Type"));
          FIELDCOPY(bondItem.m_ListedMarket,
                    CParserTool::GetString(msgBond, "ListedMarket"));
          FIELDCOPY(bondItem.m_BondID,
                    CParserTool::GetString(msgBond, "TF_ID"));  // 用tf_id来区分
          FIELDCOPY(bondItem.m_BondKey,
                    CParserTool::GetString(msgBond, "BondKey"));
          lstBond.push_back(bondItem);
        }
      }
      return ptr;
      break;
    }
    case E_FID_TF_SETTLEMENT_PRICE_REQ: {
      xQBTfSettlementPriceAck* ptr = new xQBTfSettlementPriceAck;

      ProtoList submsg_m_List;
      if (msg.GetList("List", submsg_m_List))  // List
      {
        for (auto it = submsg_m_List.begin(); it != submsg_m_List.end(); ++it) {
          if (it->Type != ProtoValue::VAR_MAP) continue;
          xQBTfSettlementPriceAckItem inner_Lis;
          const ProtoMap& msgmap = *it;

          FIELDCOPY(inner_Lis.m_Id, CParserTool::GetString(msgmap, "Id"));
          FIELDCOPY(inner_Lis.m_Time, CParserTool::GetString(msgmap, "Time"));
          msgmap.getFloat("SettPrice", inner_Lis.m_SettPrice);

          ptr->m_List.push_back(inner_Lis);
        }
      }
      return ptr;
    } break;
    default:
      break;
  }
  return nullptr;
}
